2025-04-09 Progress Report

Wrote some additional SD-card and platform-detection support. The platform is pretty straightforward. I asked in the forums about making this a variable, with no one who knew. I decided it wasn't worth figuring out compared to the other work I have to do, so I went with the "dumb" version.

object *
fn_platform(object *args, object *env)
{
    (void) args;
    (void) env;

#if defined(PLATFORM_PICOCALC)
    const char platformName[] = ":picocalc";
#elif defined(TDECK_PERI_POWERON) /* first t-deck define */
    const char platformName[] = ":t-deck";
#elif defined(ARDUINO_TEENSY41)
    const char platformName[] = ":teensy41";
#else
    const char platformName[] = ":unknown";
#endif
    return internlong((char *)platformName);
}

Writing the SD card functions, though, I learned some stuff about how uLisp works internally. Namely, creating a filename is done with MakeFilename.

object *
fn_sd_rename(object *args, object *env)
{
    (void) env;
    char buffer1[BUFFERSIZE];
    char buffer2[BUFFERSIZE];


    object *pathFrom = car(args);
    if (!stringp(pathFrom)) {
        error2("filenames must be strings.");
    }

    object *pathTo = car(cdr(args));
    if (!stringp(pathTo)) {
        error2("filenames must be strings.");
    }

    if (!SD.rename((const char *)MakeFilename(pathFrom, buffer1),
               (const char *)MakeFilename(pathTo, buffer2))) {
        return nil;
    }

    return tee;
}

Another useful thing I wanted was a list of all the symbols I'd defined that I'd lost if I powered off. list-library will print the list of symbols in the Lisp Library, but I wanted a list of symbols. So, I wrote list-library2. Basically, I just copied the core of list-library, then changed it to cons symbols to a return value:

// (list-library2)
// Return a list of all symbols in the current Lisp library.
object *
fn_listlibrary2(object *args, object *env)
{
    (void) args, (void) env;
    object *lst = nil;

    GlobalStringIndex = 0;
    object *line = read(glibrary);
    while (line != NULL) {
        builtin_t bname = builtin(first(line)->name);
        if (bname == DEFUN || bname == DEFVAR) {
            lst = cons(second(line), lst);
        }
        line = read(glibrary);
    }

    return lst;
}

Added some more code to the LispLibrary too, including a function to return all the user-defined symbols. Also, added some functionality that allows for loading platform-specific code (e.g. "platform-name.lsp").

(defun user-symbols ()
  "(user-symbols)
Returns a list of all the symbols add by a user after boot."
  (let ((library (list-library2)))
   (remove-if (lambda (sym)
                 (member sym library))
              (globals))))

(defun reset-user-environment ()
  "(reset-user-environment)
Removes all user-defined symbols."
  (mapcar 'makunbound (user-symbols)))

(defun keyword-string (k)
  "(keyword-string k)
Returns the keyword as a string, or nil if the arg isn't a keyword."
  (when (keywordp k)
   (subseq (string k) 1)))

(defun load-platform ()
 "(load-platform)
Load-platform specific code if present, found on the SD card as
platform.lsp (e.g. picocalc.lsp)."
 (let ((platform-file (concatenate 'string (keyword-string (platform)) ".lsp")))
  (when (sd-exists-p platform-file)
   (load platform-file))))

I also asked on the forums about keeping the code for multiple devices synced (specifically, the extensions and Lisp library); the recommendation was to just keep separate trees. I think I'll spend some time investigating uLisp builder.

However, I ran into a snag tonight: it looks like my screen is broken.

I think it happened while I was updating the keyboard firmware, which is unfortunate. Might be relying on the T-Deck more in the near future. It will certainly put a damper on the PicoCalc work.


Tags: ,